import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
import win32print
import win32ui
from PIL import Image, ImageWin
import logging
import traceback
import barcode


logging.basicConfig(format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s',
                    level=logging.INFO,
                    filename='info.log',
                    filemode='a')

class CodeGen:
    def gen_code(self, code):
        logging.info("class: %s, func: %s." % (self.__class__.__name__, sys._getframe().f_code.co_name))
        # 获取编码类
        try:
            Code = barcode.get_barcode_class('code128')  # 参数为支持的格式

            # 获取条形码对象
            # bar = Code("123456")
            bar = Code(code, barcode.writer.ImageWriter())
            """
            Code构造函数有3个参数：Code(code, writer=None, add_checksum=True)
            code参数为编码数据，如'123445'等
            writer参数默认值为None，此时默认使用barcodr.writer.SVGWriter()，生成的文件为SVG格式。如果想获得PNG、JPEG或BMP图像格式，需要将该参数设置为barcode.writer.ImageWriter()，例如：Code('123456',barcode.writer.ImageWriter(),False)
            add_checksum参数默认值为True，生成的条码中会自动加上校验和，如果为False，则不加校验和
            """

            # 保存条形码文件
            bar.save("./image", {"text_distance": 0.5, "dpi": 300, "font_size": 20, "module_height": 4,
                               "module_width": 0.2})  # 此处不需要输入文件后缀
            return 0
        except Exception as e:
            logging.error(str(e))
            logging.error(traceback.format_exc())
            return -1

class PrintObj:
    def __init__(self):
        self.coder = CodeGen()

    def get_all_printer(self):
        logging.info("class: %s, func: %s." % (self.__class__.__name__, sys._getframe().f_code.co_name))
        all_printer = []
        for it in win32print.EnumPrinters(2):
            all_printer.append(it[2])
        return all_printer

    def print_img(self, code_data, printer_name):
        logging.info("class: %s, func: %s." % (self.__class__.__name__, sys._getframe().f_code.co_name))
        logging.debug("code_data: %s, printer_name: %s" % (code_data, printer_name))
        if not code_data or not printer_name:
            logging.warning("code_data or printer_name is null")
            return 1

        try:
            img = "image.png"
            ret = self.coder.gen_code(code_data)
            if ret == -1:
                return 2

            # printer_name = win32print.GetDefaultPrinter()
            hDC = win32ui.CreateDC()
            hDC.CreatePrinterDC(printer_name)

            # for it in win32print.EnumPrinters(2):
            #     print(it[2])

            # 打开图片并缩放
            bmp = Image.open(img)
            if bmp.size[0] < bmp.size[1]:
                bmp = bmp.rotate(90)

            scale = 1

            hDC.StartDoc(img)
            hDC.StartPage()

            dib = ImageWin.Dib(bmp)
            scaled_width, scaled_height = [int(scale * i) for i in bmp.size]

            xpos = (454 - scaled_width) // 2

            x1 = xpos  # 控制位置
            y1 = 0
            x2 = scaled_width + xpos
            y2 = scaled_height
            logging.debug(bmp.size)
            # print(bmp.size, (x1, y1, x2, y2))
            # print(bmp.size, (x1, y1, x2, y2), scaled_width, scaled_height)
            dib.draw(hDC.GetHandleOutput(), (x1, y1, x2, y2))

            hDC.EndPage()
            hDC.EndDoc()
            hDC.DeleteDC()

            return 0
        except Exception as e:
            logging.error(str(e))
            logging.error(traceback.format_exc())
            return -1

class InputDialogDemo(QWidget):
    def __init__(self, parent=None):
        super(InputDialogDemo, self).__init__(parent)
        self.init_printer()
        self.init_dialog()

    def init_dialog(self):
        logging.info("class: %s, func: %s." % (self.__class__.__name__, sys._getframe().f_code.co_name))
        # 表单布局
        layout = QFormLayout()
        layout.setLabelAlignment(Qt.AlignCenter)
        layout.setFormAlignment(Qt.AlignCenter)
        self.setFixedSize(1000, 640)
        self.setWindowIcon(QIcon("./favicon.ico"))

        # reply = QMessageBox.question(self, '信息', '是否打印？', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        # if reply == QMessageBox.Yes:
        #     print("yes")
        # else:
        #     print("no")

        # lbl_image = QLabel()
        # png = QPixmap(r'./image.png')
        # lbl_image.setPixmap(png)

        # 创建按钮，当行文本框并建立按钮点击与槽函数的联系，添加到布局中
        self.btn1 = QPushButton('选择打印机')
        self.btn1.setFixedSize(100, 25)
        self.btn1.clicked.connect(self.getItem)
        self.printer = QLineEdit()
        self.printer.setFixedSize(250, 25)
        self.printer.setReadOnly(True)
        self.printer.setAlignment(Qt.AlignCenter)
        self.printer.setText(self.default_printer)

        layout.addRow(self.printer, self.btn1)

        self.code_data = QLineEdit()
        self.code_data.setFixedSize(250, 25)
        self.btn2 = QPushButton('打印条形码')
        self.btn2.setFixedSize(100, 25)
        self.btn2.clicked.connect(self.printValue)

        layout.addRow(self.code_data, self.btn2)

        # # 创建按钮，当行文本框并建立按钮点击与槽函数的联系，添加到布局中
        # self.btn2 = QPushButton('获得字符串')
        # self.btn2.clicked.connect(self.getText)
        # self.le2 = QLineEdit()
        # layout.addRow(self.btn2, self.le2)
        #
        # # 创建按钮，当行文本框并建立按钮点击与槽函数的联系，添加到布局中
        # self.btn3 = QPushButton('获得整数')
        # self.btn3.clicked.connect(self.getInt)
        # self.le3 = QLineEdit()
        # layout.addRow(self.btn3, self.le3)

        # 设置主窗口的布局及标题
        self.setLayout(layout)
        self.setWindowTitle('打印条形码')
        col = QColor(240, 240, 240)
        self.setStyleSheet('QWidget{background-color:%s}' % col.name())
        # self.setStyleSheet('QWidget{background-color:blue}')

    def init_printer(self):
        logging.info("class: %s, func: %s." % (self.__class__.__name__, sys._getframe().f_code.co_name))
        self.printerobj = PrintObj()
        self.all_printer_name = self.printerobj.get_all_printer()
        self.default_printer = win32print.GetDefaultPrinter()
        if not self.all_printer_name or not self.default_printer:
            reply = self.QMessageBox.warning(self, '警告', '没有打印机!请连接打印机后打印。', QMessageBox.Yes)

    def printValue(self):
        logging.info("class: %s, func: %s." % (self.__class__.__name__, sys._getframe().f_code.co_name))
        ret = self.printerobj.print_img(self.code_data.text(), self.printer.text())
        if ret == 1:
            reply = QMessageBox.warning(self, '警告', '没有打印机或者未输入条形码序列！', QMessageBox.Yes )
        elif ret == -1:
            reply = QMessageBox.warning(self, '错误', '打印错误，详情查看info.log！', QMessageBox.Yes)
        elif ret == 2:
            reply = QMessageBox.warning(self, '错误', '生成条形码错误，详情查看info.log！', QMessageBox.Yes)

    def getItem(self):
        logging.info("class: %s, func: %s." % (self.__class__.__name__, sys._getframe().f_code.co_name))
        # 创建元组并定义初始值
        # items = ('C', 'C++', 'C#', 'JAva', 'Python')
        # 获取item输入的值，以及ok键的点击与否（True 或False）
        # QInputDialog.getItem(self,标题,文本,元组,元组默认index,是否允许更改)
        item, ok = QInputDialog.getItem(self, "选择打印机", '打印机列表', self.all_printer_name, 0, False)

        if ok and item:
            # 满足条件时，设置单行文本框的文本
            self.printer.setText(item)

    def getText(self):
        logging.info("class: %s, func: %s." % (self.__class__.__name__, sys._getframe().f_code.co_name))
        text, ok = QInputDialog.getText(self, 'Text Input Dialog', '输入姓名：')
        if ok:
            self.le2.setText(str(text))

    def getInt(self):
        logging.info("class: %s, func: %s." % (self.__class__.__name__, sys._getframe().f_code.co_name))
        num, ok = QInputDialog.getInt(self, 'Integer input dualog', '输入数字')
        if ok:
            self.le3.setText(str(num))


if __name__ == '__main__':
    # WX20030600012
    # WX200306000134-2
    app = QApplication(sys.argv)
    demo = InputDialogDemo()
    demo.show()
    sys.exit(app.exec_())
